#include "oGamePreDefine.h"
#include "Actions/oRoleAction.h"
#include "oGameTypes.h"
#include "oGameEvent.h"

oRoleSwitch::oRoleSwitch( oUnit* owner ):
oAction(ACTION_ROLE_SWITCH, oID::PriorityAttack, owner)
{
	oModel* model = owner->getModel();
	_switchAnimationIndex = model->getModelDef()->getActionIndexByName("switch");
	model->animationEnd += oAnimationHandler(&oRoleSwitch::onAnimationEnd, this);
	owner->properties[oStr::IsAtSwitch] = 0;
}

oRoleSwitch::~oRoleSwitch()
{
	oModel* model = _owner->getModel();
	model->animationEnd -= oAnimationHandler(&oRoleSwitch::onAnimationEnd, this);
}

void oRoleSwitch::update( ccTime dt )
{ }

void oRoleSwitch::stop()
{
	oAction::stop();
	_owner->getModel()->stop();
}

void oRoleSwitch::run()
{
	oAction::run();
	oModel* model = _owner->getModel();
	model->setLook(oStr::noweapon);
	model->setSpeed(1.0f);
	model->setLoop(false);
	model->setRecovery(0.1f);
	model->play(_switchAnimationIndex);
	float switchflag = _owner->properties[oStr::IsAtSwitch];
	oSwitchEvent::send(
		oGetSwitchTag(switchflag),
		_owner->getGroup() == GROUP_ME,
		_owner->isFaceRight());
	if (actionStart != NULL)
	{
		actionStart(this);
	}
}

bool oRoleSwitch::isAvailable()
{
	float switchflag = _owner->properties[oStr::IsAtSwitch];
	if (switchflag > 0)
	{
		return oGetSwitchAtRight(switchflag) != _owner->isFaceRight();
	}
	return false;
}

void oRoleSwitch::onAnimationEnd( oModel* model, uint32 index )
{
	if (index == _switchAnimationIndex)
	{
		oRoleSwitch::stop();
		if (actionEnd != NULL)
		{
			actionEnd(this);
		}
	}
}

oRoleStrike::oRoleStrike( oUnit* unit ):
oAction(ACTION_ROLE_STRIKE, oID::PriorityHit, unit)
{
	oModel* model = unit->getModel();
	model->animationEnd += oAnimationHandler(&oRoleStrike::onAnimationEnd, this);
	_hitAnimationIndex = model->getModelDef()->getActionIndexByName(oID::AnimationHit);
}

oRoleStrike::~oRoleStrike()
{
	oModel* model = _owner->getModel();
	model->animationEnd -= oAnimationHandler(&oRoleStrike::onAnimationEnd, this);
}

void oRoleStrike::run()
{
	oAction::run();
#if CC_TARGET_PLATFORM == CC_PLATFORM_WIN32
	SimpleAudioEngine::sharedEngine()->playEffect("sound/hit.wav");
#endif
	oModel* model = _owner->getModel();
	model->setLook(oID::LookSad);
	model->setLoop(false);
	model->setRecovery(0.05f);
	model->setSpeed(1.0f);
	model->play(oID::AnimationHit);
	if (actionStart != NULL)
	{
		actionStart(this);
	}
}

void oRoleStrike::update( ccTime dt )
{ }

void oRoleStrike::stop()
{
	oAction::stop();
	if (actionEnd != NULL)
	{
		actionEnd(this);
	}
}

void oRoleStrike::onAnimationEnd( oModel* model, uint32 index )
{
	if (index == _hitAnimationIndex)
	{
		oRoleStrike::stop();
		if (actionEnd != NULL)
		{
			actionEnd(this);
		}
	}
}

// oRangeAttack
oVillyAttack::oVillyAttack( oUnit* unit ):
oAttack(oID::ActionRangeAttack, unit)
{ }

oAction* oVillyAttack::create( oUnit* unit )
{
	return new oVillyAttack(unit);
}

void oVillyAttack::run()
{
	oAction::run();
	_current = 0;
	_attackDelay = (5.0f/30.0f) / _owner->attackSpeed;
	_attackDelay1 = (19.0f/30.0f) / _owner->attackSpeed;
	_attackEffectDelay = _owner->getUnitDef()->attackEffectDelay / _owner->attackSpeed;
	_attackType = rand()%2;
	oModel* model = _owner->getModel();
	model->setLoop(false);
	model->setLook(_looks[0]);
	model->setRecovery(0.05f);
	model->setSpeed(_owner->attackSpeed);
	model->play(oID::AnimationAttack);
	if (actionStart != NULL)
	{
		actionStart(this);
	}
}

void oVillyAttack::update( ccTime dt )
{
	_current += dt;
	if (_attackDelay >= 0 && _current >= _attackDelay)
	{
		_attackDelay = -1;
		this->onAttack();
	}
	else if (_attackDelay1 >= 0 && _current >= _attackDelay1)
	{
		_attackDelay1 = -1;
		this->onAttack();
	}
	if (_attackEffectDelay >= 0 && _current >= _attackEffectDelay)
	{
		_attackEffectDelay = -1;
		int attackEffect = _owner->getUnitDef()->attackEffect;
		if (attackEffect != oEffectType::None)
		{
			CCPoint key = _owner->getModel()->getModelDef()->getKeyPoint(oModelDef::AttackKey);
			if (_owner->getModel()->getModelDef()->isFaceRight() != _owner->isFaceRight())
			{
				key.x = -key.x;
			}
			oEffect* effect = oSharedEffectCache.create(attackEffect);
			effect->setOffset(key)->attachTo(_owner)->autoRemove()->start();
		}
	}
}

void oVillyAttack::onAttack()
{
	oBulletDef* bulletDef = _owner->getBulletDef();
	if (bulletDef)
	{
		oBullet* bullet = bulletDef->toBullet(_owner->getWorld(), _owner);
		bullet->targetAllow = _owner->targetAllow;
		bullet->hitTarget = oBulletHandler(&oVillyAttack::onHitTarget, this);
		bullet->setScale(2.0f);
		_owner->getWorld()->addChild(bullet, _owner->getZOrder());
	}
	SimpleAudioEngine::sharedEngine()->playEffect("sound/v_att.wav");
}

bool oVillyAttack::onHitTarget( oBullet* bullet, oUnit* target )
{
	/* Get hit point */
	oHit* hitAction = (oHit*)(target->getAction(oID::ActionHit));
	if (hitAction)
	{
		b2Shape* shape = bullet->getDetectSensor()->getFixture()->GetShape();
		CCPoint hitPoint = oAttack::usePreciseHit ? oAttack::getHitPoint(_owner, target, shape) : target->getPosition();
		bool attackRight = bullet->getVelocityX() > 0.0f;
		hitAction->setHitInfo(hitPoint, _owner->attackPower, !attackRight);
	}
	/* Make damage */
	float damage = oAttack::getDamage(target);
	target->hp -= damage;
	if (damaged != NULL)
	{
		damaged(_owner, target, damage);
	}
	return true;
}

string oVillyAttack::_looks[4] =
{
	string("mech"),
	string("lauchr"),
	string("gun"),
	string("refle")
};
